package com.sds.thesis.policy;

import java.util.Iterator;
import java.util.List;

import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.exception.RenderException;
import com.deepoove.poi.policy.RenderPolicy;
import com.deepoove.poi.render.compute.EnvModel;
import com.deepoove.poi.render.compute.RenderDataCompute;
import com.deepoove.poi.render.processor.DocumentProcessor;
import com.deepoove.poi.render.processor.EnvIterator;
import com.deepoove.poi.resolver.TemplateResolver;
import com.deepoove.poi.template.ElementTemplate;
import com.deepoove.poi.template.MetaTemplate;
import com.deepoove.poi.template.run.RunTemplate;
import com.deepoove.poi.util.ReflectionUtils;
import com.deepoove.poi.util.TableTools;

/**
 * 循环表行渲染策略
 */
public class LoopRowTableRenderPolicy implements RenderPolicy {

    // 前缀
    private String prefix;
    // 后缀
    private String suffix;
    // 是否在同一行
    private boolean onSameLine;

    public LoopRowTableRenderPolicy() {
        this(false);
    }

    public LoopRowTableRenderPolicy(boolean onSameLine) {
        this("[", "]", onSameLine);
    }

    public LoopRowTableRenderPolicy(String prefix, String suffix) {
        this(prefix, suffix, false);
    }

    public LoopRowTableRenderPolicy(String prefix, String suffix, boolean onSameLine) {
        this.prefix = prefix;
        this.suffix = suffix;
        this.onSameLine = onSameLine;
    }

    @Override
    public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
        RunTemplate runTemplate = (RunTemplate) eleTemplate;
        XWPFRun run = runTemplate.getRun();
        try {
            if (!TableTools.isInsideTable(run)) {
                throw new IllegalStateException(
                        "模板标签 " + runTemplate.getSource() + " 必须在表格内");
            }
            // 获取标签所在的单元格
            XWPFTableCell tagCell = (XWPFTableCell) ((XWPFParagraph) run.getParent()).getBody();
            XWPFTable table = tagCell.getTableRow().getTable();
            run.setText("", 0);

            // 获取模板行索引
            int templateRowIndex = getTemplateRowIndex(tagCell);

            // 如果数据不为空且是可迭代的
            if (null != data && data instanceof Iterable) {
                Iterator<?> iterator = ((Iterable<?>) data).iterator();
                // 获取模板行
                XWPFTableRow templateRow = table.getRow(templateRowIndex);
                int insertPosition = templateRowIndex;

                // 创建模板解析器
                TemplateResolver resolver = new TemplateResolver(template.getConfig().copy(prefix, suffix));
                boolean firstFlag = true;
                int index = 0;
                boolean hasNext = iterator.hasNext();

                // 循环迭代
                while (hasNext) {
                    Object root = iterator.next();
                    hasNext = iterator.hasNext();

                    // 插入位置
                    insertPosition = templateRowIndex++;
                    // 插入新行
                    XWPFTableRow nextRow = table.insertNewTableRow(insertPosition);
                    // 设置行
                    setTableRow(table, templateRow, insertPosition);

                    // 双重设置行
                    XmlCursor newCursor = templateRow.getCtRow().newCursor();
                    // 获取下一个兄弟节点
                    newCursor.toPrevSibling();
                    // 获取对象
                    XmlObject object = newCursor.getObject();
                    nextRow = new XWPFTableRow((CTRow) object, table);
                    if (!firstFlag) {
                        // 更新非首行的合并单元格
                        List<XWPFTableCell> tableCells = nextRow.getTableCells();
                        for (XWPFTableCell cell : tableCells) {
                            // 获取单元格属性
                            CTTcPr tcPr = TableTools.getTcPr(cell);
                            // 获取垂直合并
                            CTVMerge vMerge = tcPr.getVMerge();
                            if (null == vMerge) continue;
                            // 如果是重启，则设置为继续
                            if (STMerge.RESTART == vMerge.getVal()) {
                                vMerge.setVal(STMerge.CONTINUE);
                            }
                        }
                    } else {
                        firstFlag = false;
                    }
                    // 设置行
                    setTableRow(table, nextRow, insertPosition);

                    // 创建数据计算
                    RenderDataCompute dataCompute = template.getConfig()
                            .getRenderDataComputeFactory()
                            .newCompute(EnvModel.of(root, EnvIterator.makeEnv(index++, hasNext)));
                    List<XWPFTableCell> cells = nextRow.getTableCells();
                    // 处理单元格
                    cells.forEach(cell -> {
                        List<MetaTemplate> templates = resolver.resolveBodyElements(cell.getBodyElements());
                        new DocumentProcessor(template, resolver, dataCompute).process(templates);
                    });
                }
            }

            // 移除模板行
            table.removeRow(templateRowIndex);
            afterloop(table, data);
        } catch (Exception e) {
            throw new RenderException("HackLoopTable for " + eleTemplate + " 错误: " + e.getMessage(), e);
        }
    }

    /**
     * 循环结束后执行
     */
    private int getTemplateRowIndex(XWPFTableCell tagCell) {
        XWPFTableRow tagRow = tagCell.getTableRow();
        return onSameLine ? getRowIndex(tagRow) : (getRowIndex(tagRow) + 1);
    }

    protected void afterloop(XWPFTable table, Object data) {
    }

    /**
     * 设置行
     */
    @SuppressWarnings("unchecked")
    private void setTableRow(XWPFTable table, XWPFTableRow templateRow, int pos) {
        // 获取表格行
        List<XWPFTableRow> rows = (List<XWPFTableRow>) ReflectionUtils.getValue("tableRows", table);
        // 设置行
        rows.set(pos, templateRow);
        // 设置表格行
        table.getCTTbl().setTrArray(pos, templateRow.getCtRow());
    }

    /**
     * 获取行索引
     */
    private int getRowIndex(XWPFTableRow row) {
        List<XWPFTableRow> rows = row.getTable().getRows();
        return rows.indexOf(row);
    }

}
